/*
 * Project: push-center-service-impl
 * 
 * File Created at 2014-10-9
 * 
 * Copyright 2012 Greenline.com Corporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * Greenline Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Greenline.com.
 */
package com.greenline.push.service.core.send;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.util.CollectionUtils;

import com.greenline.gateway.base.BaseParamPO;
import com.greenline.gateway.base.ResponseCode;
import com.greenline.gateway.base.ResponseDTO;
import com.greenline.gateway.enums.AppType;
import com.greenline.gateway.service.weixin.GroupMsgService;
import com.greenline.gateway.service.weixin.WXTemplateMsgService;
import com.greenline.gateway.service.weixin.po.GroupMsgTextPO;
import com.greenline.gateway.service.weixin.po.TemplateModelPO;
import com.greenline.gateway.service.weixin.po.TemplateMsgSendPO;
import com.greenline.push.core.enums.Channels;
import com.greenline.push.core.enums.MsgSendType;
import com.greenline.push.core.enums.Tasks;
import com.greenline.push.service.core.exception.ChannelSendException;
import com.greenline.push.service.core.item.AppPacket;
import com.greenline.push.service.core.item.Packet;
import com.greenline.push.service.core.send.base.AbstractSender;
import com.greenline.push.service.core.send.base.AppPacketHandler;
import com.greenline.push.service.core.tmpl.AppChannelCache;
import com.greenline.push.service.core.tmpl.GroupAppCache;
import com.greenline.push.service.core.user.AppUserInfo;
import com.greenline.push.service.core.utils.Constants;

/**
 * WeixinSender
 * 
 * @author weirui.shenwr
 * @date 2014-10-9
 * @version V1.0
 */
public class WeixinSender extends AbstractSender {
    @Resource
    private WXTemplateMsgService wxTemplateMsgService;
    @Resource
    private AppChannelCache appChannelCache;
    @Resource
    private GroupMsgService wxGroupMsgService;
    @Resource
    private GroupAppCache groupAppCache;
    @Resource
    private AppPacketHandler packetHandler;

    Logger log = Constants.LOG_PROCESS;

    @Override
    public Channels supportChannel() {
        return Channels.weixin;
    }

    @Override
    protected boolean doSend(Packet packet) {
        //
        AppPacket appPacket = (AppPacket) packet;
        log.info(String
                .format("{weixinSender收到数据}:准备发送***domainId:[%s].tempId:[%s].type:[%s],extparam-context:[%s-%s],source:[%s],retryId:[%s],thread:[%s]",
                        appPacket.getDomainId(), appPacket.getTemplateId(), appPacket.getType(), appPacket.getExtParam(),
                        appPacket.getContext(), appPacket.getSource(), appPacket.getDbRetryId(), Thread.currentThread().getName()));

        ResponseDTO<Boolean> result = null;
        try {
            // 模版发送
            if (MsgSendType.POINT.getType() == appPacket.getType()) {
                result = this.sendPoint(appPacket);
            } else
            // 全部发送
            if (MsgSendType.ALL.getType() == appPacket.getType()) {
                result = this.sendAll(appPacket);
            } else
            // 分组发送
            if (MsgSendType.GROUP.getType() == appPacket.getType()) {
                this.sendGroup(appPacket);
            } else if (MsgSendType.UPLOAD.getType() == appPacket.getType() || MsgSendType.CONDITIONS.getType() == appPacket.getType()
                    || MsgSendType.DOMAIN.getType() == appPacket.getType()) {
                // upload 或者 condition 类型 可以调用第三方按组发送
                this.sendList(appPacket);
            }
        } catch (Exception e) {
            result = new ResponseDTO<Boolean>();
            result.setResult(ResponseCode.ERROR, e.getMessage());
            packetHandler.afterSendOperation(appPacket, false);
            log.error(String.format("{weixinSender发送异常}接受者%s.模板id:%s.异常信息", packet.getRecvUserId(), packet.getTemplateId(), e.getMessage()));
        }
        // 一下是测试代码
        // try {
        // Thread.sleep(90);
        // // return true;
        // } catch (InterruptedException e1) {
        // // TODO Auto-generated catch block
        // e1.printStackTrace();
        // }
        // super.afterSendOperation(appPacket, true);
        return true;
    }

    private void sendList(AppPacket appPacket) {
        Long retryId = appPacket.getDbRetryId();
        String appId = appPacket.getAppId();

        List<String> sResult = getUserIdsByRetryId(retryId);
        if (sResult == null) {
            log.error(String.format("{weixin.sendList}发送失败,apppacket下没有取到用户.retryId:%s,context:%s", retryId, appPacket.getContext()));
            packetHandler.afterSendOperation(appPacket, false, true);
            return;
        }
        log.debug(String.format("{weixin***sendList}批量发送weixin消息.uidlist:%s.contenxt:[%s],retryId:[%s]", sResult.toString(),
                appPacket.getContext(), appPacket.getDbRetryId()));
        // convert to p2p
        for (String userId : sResult) {
            AppUserInfo userInfo = getAppUser(userId, appId);
            if (null == userInfo)
                continue;
            appPacket.setRecvUserId(Long.valueOf(userId));
            appPacket.setDeviceToken(userInfo.getDeviceToken());
            try {
                sendPoint(appPacket);
            } catch (ChannelSendException e) {
                e.printStackTrace();
                packetHandler.afterSendOperation(appPacket, false);
            }
        }
        // getAppUser(userId, appId)
    }

    /**
     * 发送点对点消息
     * 
     * @param appPacket
     * @return
     * @throws ChannelSendException
     */
    private ResponseDTO<Boolean> sendPoint(AppPacket appPacket) throws ChannelSendException {
        String methodName = "{weixinSender.sendPoint}";
        BaseParamPO<TemplateMsgSendPO> param = new BaseParamPO<TemplateMsgSendPO>();
        String extAppId = appChannelCache.getExtAppId(appPacket.getAppChannelId());
        if (extAppId == null) {
            packetHandler.afterSendOperation(appPacket, false, true);
            log.error(String.format("[%s].未获取extAppId,推送失败.内容:[%s]", methodName, appPacket.getContext()));
            throw new ChannelSendException("应用：" + appPacket.getAppId() + "不存在。");
        }
        param.setAppId(extAppId);
        param.setAppType(AppType.WEIXIN.getValue());
        TemplateMsgSendPO template = new TemplateMsgSendPO();
        template.setTemplate_id(appPacket.getExtTemplId());
        template.setTouser(appPacket.getDeviceToken());
        if (!CollectionUtils.isEmpty(appPacket.getExtParam())) {
            template.setUrl(appPacket.getExtParam().get("url"));
            Map<String, TemplateModelPO> data = new HashMap<String, TemplateModelPO>();
            for (Entry<String, String> entry : appPacket.getExtParam().entrySet()) {
                TemplateModelPO templateModelPO = new TemplateModelPO();
                templateModelPO.setValue(entry.getValue());
                data.put(entry.getKey(), templateModelPO);
            }
            template.setData(data);
        }
        param.setParam(template);
        ResponseDTO<Boolean> result = null;
        try {
            result = wxTemplateMsgService.sendTemplateMsg(param);
            log.info(String.format("%s发送完成:结果:[%s--%s]***domainId:[%s].tempId:[%s].extparam:[%s].接收人:[%s-%s].发送内容:[%s].retryId:[%s]",
                    methodName, result.getCode(), result.getMessage(), appPacket.getDomainId(), appPacket.getTemplateId(),
                    appPacket.getExtParam(), appPacket.getRecvUserId(), appPacket.getDeviceToken(), appPacket.getContext(),
                    appPacket.getDbRetryId()));
            // log
            packetHandler.afterSendOperation(appPacket, result.getDataResult());
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            packetHandler.afterSendOperation(appPacket, false);
            log.error(String.format("%s.远程接口调用失败,异常信息:%s.内容:%s", methodName, e.getMessage(), appPacket.getContext()));
            return result;
        }
    }

    // 全部发送
    private ResponseDTO<Boolean> sendAll(AppPacket appPacket) throws ChannelSendException {
        ResponseDTO<Boolean> result = new ResponseDTO<Boolean>();
        Set<String> set = groupAppCache.loadByAppId(appPacket.getAppId());
        String extAppId = appChannelCache.getExtAppId(appPacket.getAppChannelId());
        if (extAppId == null) {
            throw new ChannelSendException("应用：" + appPacket.getAppId() + "不存在。");
        }

        for (String groupId : set) {
            BaseParamPO<GroupMsgTextPO> po = new BaseParamPO<GroupMsgTextPO>();
            po.setAppId(extAppId);
            po.setAppType(AppType.WEIXIN.getValue());
            GroupMsgTextPO param = new GroupMsgTextPO();
            param.setContent(appPacket.getContext());
            param.setGroupId(groupId);
            po.setParam(param);
            wxGroupMsgService.sendText(po);
        }
        result.setDataResult(true);
        // log
        packetHandler.afterSendOperation(appPacket, result.getDataResult());
        return result;
    }

    private void sendGroup(AppPacket appPacket) throws ChannelSendException {

        log.debug(String.format("{weixin**sendGroup开始推送}context:%s,gid:%s", appPacket.getContext(), appPacket.getRecvUserId()));

        String relativeGroupId = groupAppCache.loadByGroupId(appPacket.getAppChannelId(), appPacket.getRecvUserId());
        if (StringUtils.isBlank(relativeGroupId)) {
            Long gid = appPacket.getRecvUserId();
            List<Long> userIds = getUserIdsbyGid(gid);
            for (Long userId : userIds) {
                AppUserInfo ucontact = getAppUser(userId, appPacket.getAppId());
                if (ucontact == null)
                    continue;
                // 转化成point
                appPacket.setRecvUserId(userId);
                appPacket.setDeviceToken(ucontact.getDeviceToken());
                sendPoint(appPacket);
            }
        } else {
            // send group directly
            ResponseDTO<Boolean> result = new ResponseDTO<Boolean>();
            BaseParamPO<GroupMsgTextPO> po = new BaseParamPO<GroupMsgTextPO>();
            String extAppId = appChannelCache.getExtAppId(appPacket.getAppChannelId());
            if (extAppId == null) {
                throw new ChannelSendException("应用：" + appPacket.getAppId() + "不存在。");
            }

            po.setAppId(extAppId);
            po.setAppType(AppType.WEIXIN.getValue());
            GroupMsgTextPO param = new GroupMsgTextPO();
            // 此时recvuserid表示gid
            appPacket.setContext(appPacket.getExtParam().get(Constants.GLOBAL_MAP_CONTENT_KEY));
            param.setGroupId(relativeGroupId);
            po.setParam(param);
            ResponseDTO<String> rsponse = wxGroupMsgService.sendText(po);
            if (ResponseCode.SUCCESS.equals(rsponse.getCode())) {
                result.setDataResult(true);
            } else {
                result.setResult(ResponseCode.EXCEPTION, rsponse.getMessage());
            }
            packetHandler.afterSendOperation(appPacket, result.getDataResult());
        }
    }

    // 群组发送
    // private ResponseDTO<Boolean> sendGroup(AppPacket appPacket) throws
    // ChannelSendException {
    // ResponseDTO<Boolean> result = new ResponseDTO<Boolean>();
    // BaseParamPO<GroupMsgTextPO> po = new BaseParamPO<GroupMsgTextPO>();
    // String extAppId =
    // appChannelCache.getExtAppId(appPacket.getAppChannelId());
    // if (extAppId == null) {
    // throw new ChannelSendException("应用：" + appPacket.getAppId() + "不存在。");
    // }
    //
    // po.setAppId(extAppId);
    // po.setAppType(AppType.WEIXIN.getValue());
    // GroupMsgTextPO param = new GroupMsgTextPO();
    // param.setContent(appPacket.getContext());
    // // 此时recvuserid表示gid
    // param.setGroupId(groupAppCache.loadByGroupId(appPacket.getAppChannelId(),
    // appPacket.getRecvUserId()));
    // po.setParam(param);
    // ResponseDTO<String> rsponse = wxGroupMsgService.sendText(po);
    // if (ResponseCode.SUCCESS.equals(rsponse.getCode())) {
    // result.setDataResult(true);
    // } else {
    // result.setResult(ResponseCode.EXCEPTION, rsponse.getMessage(), false);
    // }
    // return result;
    // }

    @Override
    protected Tasks getTaskType() {
        return Tasks.FETCH_RETRY_WEIXIN;
    }

    @Override
    protected String getQueueName() {
        return "weixin推送处理队列";
    }

    @Override
    protected Tasks getFullTaskType() {
        return Tasks.FETCH_RETRY_WEIXIN_FULL;
    }

    @Override
    protected String getFullQueueName() {
        return "weixin全量推送处理队列";
    }

}
